package de.mmis.core.base.abstracttree.serializer.internal;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import de.mmis.core.base.DeserializableAnnotations.DeserializationMethod;
import de.mmis.core.base.DeserializableAnnotations.EnumDeserializable;
import de.mmis.core.base.abstracttree.InnerNode;
import de.mmis.core.base.abstracttree.LeafNode;
import de.mmis.core.base.abstracttree.Tree;
import de.mmis.core.base.abstracttree.Tree.Type;
import de.mmis.core.base.abstracttree.serializer.DeserializableException;
import de.mmis.core.base.abstracttree.serializer.Serializer;
import de.mmis.core.base.abstracttree.serializer.SerializerHelper;
import de.mmis.core.base.gclass.GClass;

/**
 * Serializer class for (de)serializing enumerations from/to Trees
 * 
 * @author Christian Koch
 */
public class EnumSerializer implements Serializer<Enum<?>> {

	@DeserializationMethod
	public static Object deserialize(Tree[] exps, ClassLoader classLoader,
			String id, Map<String, Object> idmap)
			throws DeserializableException {

		if (exps.length != 2)
			throw new DeserializableException(new InnerNode(exps),
					"enum Tree needs 2 parameters");

		Class<?> enumClass = (Class<?>) SerializerHelper.deserializeObject(
				exps[0], GClass.fromClass(Class.class), classLoader, idmap);
		if (exps[1].getType() != Type.LEAF)
			throw new DeserializableException(new InnerNode(exps),
					"enum name has to be an atom");

		return getEnumConstant((LeafNode) exps[1], enumClass);
	}

	public static Object getEnumConstant(LeafNode exp, Class<?> enumClass)
			throws DeserializableException {
		String name = exp.getUTF8Data();
		List<?> list = Arrays.asList(enumClass.getEnumConstants());
		for (int i = 0; i < list.size(); i++) {
			if (list.get(i).toString().equals(name))
				return list.get(i);
		}
		throw new DeserializableException(exp, "item \"" + name
				+ "\" is not element of enum \"" + enumClass.getName() + "\"");
	}

	@Override
	public Tree serialize(Enum<?> object, boolean explicit,
			Map<Object, String> refmap, ClassLoader classLoader) {
		Tree ret = new LeafNode(object.toString());
		if (explicit) {
			EnumDeserializable a = object.getClass().getAnnotation(
					EnumDeserializable.class);
			if (a != null)
				ret = new InnerNode(new LeafNode(
						SerializerHelper.typeIdentifierPrefix
								+ a.typeIdentifier()), ret);
			else
				ret = new InnerNode(new LeafNode(
						SerializerHelper.typeIdentifierPrefix + "java-enum"),
						Tree.fromObject(object.getClass(), explicit, refmap,
								classLoader), ret);
		}
		return ret;
	}
}
